package editor.code;

import event.TextReplacementEvent;
import model.caret.CaretRef;
import model.code.CodeFileChunk;
import model.code.line.Line;
import model.code.line.SingleLine;
import observer.ObservedLong;
import util.ArrayUtil;
import util.StringUtil;

/**
 * @author Neil Dickson
 */
public class NumberField extends LineField {
	private ObservedLong	value;
	private int				radix;
	public NumberField(ObservedLong value,int radix,long defaultValue,CaretRef caretRef) {
		super(new NumberLine(value,radix,defaultValue), caretRef, true);
		lines.get(0).addReference(value.get(),0,false);
		this.value = value;
		this.radix = radix;
	}

	public void setObservedLong(ObservedLong newValue,long defaultValue) {
		lines = new NumberLine(newValue,radix,defaultValue);
		value = newValue;
		repaint();
		ensureValidCaret();
	}

	public ObservedLong getObservedLong() {
		return value;
	}

	public static class NumberLine extends SingleLine {
		final ObservedLong value;
		final int 	radix;
		final long	defaultValue;
		public NumberLine(ObservedLong value,int radix,long defaultValue) {
			super(Long.toString(value.get(),radix).toUpperCase().toCharArray(),null,CodeFileChunk.LOCATION_NOWHERE);
			this.value = value;
			this.radix = radix;
			this.defaultValue = defaultValue;
			addReference(value.get(),0,false);
			trimToSize();
		}

		public TextReplacementEvent replace(LineObserver culprit,int startCol, int endCol, char[] newText) {
			char[] adjusted = StringUtil.reduceToNumber((toString(0,startCol)+new String(newText)+toString(endCol,length())).toCharArray(),radix);
			long newValue = defaultValue;
			int length;
			for (length=adjusted.length;length>0;--length) {
				try {
					newValue = Long.parseLong(new String(adjusted,0,length),radix);
					break;
				}
				catch (NumberFormatException e) {
					// Try again with a shorter string
				}
			}
			if (value.get()!=newValue) {
				value.set(newValue);
				references[0] = newValue;
			}
			int start;
			for (start=0;start<length && start<length() && adjusted[start]==text[start];++start) {}
			int end;
			int adjustedEnd = adjusted.length;
			for (end=length();end>0 && adjustedEnd>0 && adjusted[adjustedEnd-1]==text[end-1];--end) {--adjustedEnd;}
			// If something has changed
			if (start<=end) {
				return super.replace(culprit,start,end, ArrayUtil.subarray(adjusted,start,adjustedEnd));
			}
			// If the length has changed without having a change in content that is caught above, (e.g. "200" changing to "2000")
			else if (length()!=adjusted.length) {
				return super.replace(culprit,startCol,startCol+Math.max(0,length()-adjusted.length), ArrayUtil.subarray(adjusted,startCol,startCol+Math.max(0,adjusted.length-length())));
			}
			// If nothing has changed, do nothing, but do it at the right location so that the caret isn't messed up.
			else {
				return super.replace(culprit,endCol,endCol,Line.EMPTY_CHAR_ARRAY);
			}
		}
	}
}
